package com.hupu.jrs.widget

import android.content.Context
import android.content.res.TypedArray
import android.graphics.Color
import android.graphics.Paint
import android.graphics.drawable.ColorDrawable
import android.text.InputFilter
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.NumberPicker
import com.hupu.jrs.R
import java.lang.reflect.Field

/**
 * Created by sll on 2016/4/1.
 */
class MaterialNumberPicker : NumberPicker {

    val builder: Builder = null!!
    /**
     * Uses reflection to access text color private attribute for both wheel and edit text inside the
     * number picker.
     */
    var textColor: Int = 0
        set(textColor) {
            field = textColor
            updateTextAttributes()
        }
    private var mTextSize: Float = 0.toFloat()
    /**
     * Uses reflection to access divider private attribute and override its color
     * Use Color.Transparent if you wish to hide them
     */
    var separatorColor: Int = 0
        set(separatorColor) {
            field = separatorColor

            val pickerFields = NumberPicker::class.java.declaredFields
            for (pf in pickerFields) {
                if (pf.name == "mSelectionDivider") {
                    pf.isAccessible = true
                    try {
                        pf.set(this, ColorDrawable(separatorColor))
                    } catch (e: IllegalAccessException) {
                        e.printStackTrace()
                    } catch (e: IllegalArgumentException) {
                        e.printStackTrace()
                    }

                    break
                }
            }
        }
    var isFocusabilityEnabled: Boolean = false
        private set

    constructor(context: Context) : super(context) {
        initView()
    }

    constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
        initView()

        val a = context.obtainStyledAttributes(attributeSet, R.styleable.MaterialNumberPicker)

        for (i in 0 until a.indexCount) {

            val attr = a.getIndex(i)
            if (attr == R.styleable.MaterialNumberPicker_npMinValue) {
                minValue = a.getInt(attr, MIN_VALUE)
            } else if (attr == R.styleable.MaterialNumberPicker_npMaxValue) {
                maxValue = a.getInt(attr, MAX_VALUE)
            } else if (attr == R.styleable.MaterialNumberPicker_npDefaultValue) {
                value = a.getInt(attr, DEFAULT_VALUE)
            } else if (attr == R.styleable.MaterialNumberPicker_npTextSize) {
                setTextSize(a.getDimension(attr, TEXT_SIZE))
            } else if (attr == R.styleable.MaterialNumberPicker_npTextColor) {
                textColor = a.getColor(attr, TEXT_COLOR)
            } else if (attr == R.styleable.MaterialNumberPicker_npSeparatorColor) {
                separatorColor = a.getColor(attr, SEPARATOR_COLOR)
            } else if (attr == R.styleable.MaterialNumberPicker_npFocusValue) {
                setFocusability(a.getBoolean(attr, false))
            } else if (attr == R.styleable.MaterialNumberPicker_npWrapValue) {
                wrapSelectorWheel = a.getBoolean(attr, false)
            } else if (attr == R.styleable.MaterialNumberPicker_npBackground) {
                setBackgroundColor(a.getColor(attr, BACKGROUND_COLOR))
            }
        }

        a.recycle()
    }

    constructor(builder: Builder) : super(builder.context) {
        initView()

        this.builder = builder

        minValue = builder.minValue
        maxValue = builder.maxValue
        value = builder.defaultValue
        setFormatter(builder.formatter)
        setBackgroundColor(builder.backgroundColor)
        separatorColor = builder.separatorColor
        textColor = builder.textColor
        setTextSize(spToPixels(context, builder.textSize))
        wrapSelectorWheel = builder.wrapSelectorWheel
        setFocusability(builder.enableFocusability)
    }

    /**
     * Init number picker by disabling focusability of edit text embedded inside the number picker
     * We also override the edit text filter private attribute by using reflection as the formatter
     * is
     * still buggy while attempting to display the default value
     * This is still an open Google @see [issue](https://code.google.com/p/android/issues/detail?id=35482#c9)
     * from 2012
     */
    private fun initView() {
        minValue = MIN_VALUE
        maxValue = MAX_VALUE
        value = DEFAULT_VALUE
        setBackgroundColor(BACKGROUND_COLOR)
        separatorColor = SEPARATOR_COLOR
        textColor = TEXT_COLOR
        setTextSize(TEXT_SIZE)
        wrapSelectorWheel = false
        setFocusability(false)

        try {
            val f = NumberPicker::class.java.getDeclaredField("mInputText")
            f.isAccessible = true
            val inputText = f.get(this) as EditText
            inputText.filters = arrayOfNulls(0)
        } catch (e: NoSuchFieldException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        } catch (e: IllegalArgumentException) {
            e.printStackTrace()
        }

    }

    /**
     * Uses reflection to access text size private attribute for both wheel and edit text inside the
     * number picker.
     */
    fun setTextSize(textSize: Float) {
        mTextSize = textSize
        updateTextAttributes()
    }

    private fun updateTextAttributes() {
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            if (child is EditText) {
                try {
                    val selectorWheelPaintField = NumberPicker::class.java.getDeclaredField("mSelectorWheelPaint")
                    selectorWheelPaintField.isAccessible = true

                    val wheelPaint = selectorWheelPaintField.get(this) as Paint
                    wheelPaint.color = textColor
                    wheelPaint.textSize = mTextSize

                    child.setTextColor(textColor)
                    child.textSize = pixelsToSp(context, mTextSize)

                    invalidate()
                    break
                } catch (e: NoSuchFieldException) {
                    e.printStackTrace()
                } catch (e: IllegalAccessException) {
                    e.printStackTrace()
                } catch (e: IllegalArgumentException) {
                    e.printStackTrace()
                }

            }
        }
    }

    private fun setFocusability(isFocusable: Boolean) {
        isFocusabilityEnabled = isFocusable
        descendantFocusability = if (isFocusable) ViewGroup.FOCUS_AFTER_DESCENDANTS else ViewGroup.FOCUS_BLOCK_DESCENDANTS
    }

    private fun pixelsToSp(context: Context, px: Float): Float {
        return px / context.resources.displayMetrics.scaledDensity
    }

    private fun spToPixels(context: Context, sp: Float): Float {
        return sp * context.resources.displayMetrics.scaledDensity
    }

    class Builder(private val context: Context) {
        private var formatter: NumberPicker.Formatter? = null
        private var backgroundColor = BACKGROUND_COLOR
        private var separatorColor = SEPARATOR_COLOR
        private var textColor = TEXT_COLOR
        private var textSize = TEXT_SIZE
        private var minValue = MIN_VALUE
        private var maxValue = MAX_VALUE
        private var defaultValue = DEFAULT_VALUE
        private var enableFocusability = false
        private var wrapSelectorWheel = false

        fun formatter(formatter: NumberPicker.Formatter): Builder {
            this.formatter = formatter
            return this
        }

        fun backgroundColor(backgroundColor: Int): Builder {
            this.backgroundColor = backgroundColor
            return this
        }

        fun separatorColor(separatorColor: Int): Builder {
            this.separatorColor = separatorColor
            return this
        }

        fun textColor(textColor: Int): Builder {
            this.textColor = textColor
            return this
        }

        fun textSize(textSize: Float): Builder {
            this.textSize = textSize
            return this
        }

        fun minValue(minValue: Int): Builder {
            this.minValue = minValue
            return this
        }

        fun maxValue(maxValue: Int): Builder {
            this.maxValue = maxValue
            return this
        }

        fun defaultValue(defaultValue: Int): Builder {
            this.defaultValue = defaultValue
            return this
        }

        fun wrapSelectorWheel(wrapSelectorWheel: Boolean): Builder {
            this.wrapSelectorWheel = wrapSelectorWheel
            return this
        }

        fun enableFocusability(enableFocusability: Boolean): Builder {
            this.enableFocusability = enableFocusability
            return this
        }

        fun build(): MaterialNumberPicker {
            return MaterialNumberPicker(this)
        }
    }

    companion object {

        private val MIN_VALUE = 1
        private val MAX_VALUE = 10
        private val DEFAULT_VALUE = 1
        private val TEXT_SIZE = 20f
        private val TEXT_COLOR = Color.BLACK
        private val BACKGROUND_COLOR = Color.WHITE
        private val SEPARATOR_COLOR = Color.TRANSPARENT
    }
}
